package com.klun.project.dal.common.loadbalance;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

public class RoundRobinLoadBalance implements LoadBalance<String> {
	private static final int MIN_LB_FACTOR = 1;
	private List<String> targets;
	private int currentPos = 0;

	public RoundRobinLoadBalance(Map<String, Integer> lbFactors) {
		Assert.notEmpty(lbFactors, "lbFactors must not null");
		this.targets = this.initTargets(lbFactors);
	}

	public List<String> initTargets(Map<String, Integer> lbFactors) {
		if (lbFactors != null && lbFactors.size() != 0) {
			this.fixFactor(lbFactors);
			Collection<Integer> factors = lbFactors.values();
			int min = (Integer) Collections.min(factors);
			return min > 1 && this.canModAll(min, factors) ? this.buildBalanceTargets(lbFactors, min) : this.buildBalanceTargets(lbFactors, 1);
		} else {
			return null;
		}
	}

	private void fixFactor(Map<String, Integer> lbFactors) {
		Iterator var2 = lbFactors.entrySet().iterator();

		while(var2.hasNext()) {
			Map.Entry<String, Integer> entry = (Map.Entry)var2.next();
			if ((Integer)entry.getValue() < 1) {
				entry.setValue(1);
			}
		}

	}

	private boolean canModAll(int baseFactor, Collection<Integer> factors) {
		Iterator var3 = factors.iterator();

		Integer factor;
		do {
			if (!var3.hasNext()) {
				return true;
			}

			factor = (Integer)var3.next();
		} while(factor % baseFactor == 0);

		return false;
	}

	private List<String> buildBalanceTargets(Map<String, Integer> lbFactors, int baseFactor) {
		List<String> targets = new ArrayList();
		Iterator var4 = lbFactors.entrySet().iterator();

		while(var4.hasNext()) {
			Map.Entry<String, Integer> entry = (Map.Entry)var4.next();
			int count = (Integer)entry.getValue() / baseFactor;

			for(int i = 0; i < count; ++i) {
				targets.add(entry.getKey());
			}
		}

		return targets;
	}

	public synchronized String elect() {
		if (CollectionUtils.isEmpty(this.targets)) {
			return null;
		} else {
			if (this.currentPos >= this.targets.size()) {
				this.currentPos = 0;
			}

			return (String)this.targets.get(this.currentPos++);
		}
	}
}